package main

import (
	"fmt"
	"os"
	"path/filepath"
	"plugin"

	fileviewplugin "gitee.com/liuxyz/file-view-plugin"
	"github.com/gin-gonic/gin"
)

func LoadPlugins(router *gin.Engine, pluginDir string) ([]fileviewplugin.PluginInfo, error) {
	entries, err := os.ReadDir(pluginDir)
	if err != nil {
		return nil, err
	}

	loadedPluginsMap := make(map[string]struct{})
	loadedPlugins := make([]fileviewplugin.PluginInfo, 0)

	for _, entry := range entries {
		if entry.IsDir() {

			pluginSo := filepath.Join(pluginDir, entry.Name(), "plugin.so")

			pluginInfo := fileviewplugin.PluginInfo{
				Path: pluginSo,
			}

			plName, plRouter, err := loadPlugin(pluginSo)
			if err != nil {
				pluginInfo.Err = err.Error()
				loadedPlugins = append(loadedPlugins, pluginInfo)
				continue
			}

			pluginInfo.Name = plName
			if _, ok := loadedPluginsMap[plName]; ok {
				pluginInfo.Err = fmt.Sprintf("plugin %s already loaded, path: %s", plName, pluginSo)
				loadedPlugins = append(loadedPlugins, pluginInfo)
				continue
			}

			for path, handler := range plRouter {
				router.POST(fmt.Sprintf("/api/%s/%s", plName, path), handler)
			}

			pluginInfo.Name = plName
			loadedPlugins = append(loadedPlugins, pluginInfo)
		}
	}

	return loadedPlugins, nil
}

func loadPlugin(pluginSo string) (string, map[string]gin.HandlerFunc, error) {
	p, err := plugin.Open(pluginSo)
	if err != nil {
		return "", nil, err
	}

	pluginDef, err := p.Lookup("NewPlugin")
	if err != nil {
		return "", nil, err
	}
	newPlugin := pluginDef.(func() fileviewplugin.Plugin)
	pl := newPlugin()

	return pl.Name(), pl.ExportRouter(), nil
}
